package com.jp.fm.dao;

import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.jp.fm.EasyMockParent;
import com.jp.fm.data.Category;
import com.jp.fm.data.Transaction;
import com.jp.fm.service.TransactionService;

public class TransactionDaoTest extends EasyMockParent {

	private TransactionDao transactionDao = null;
	private AccountDao accountDao = null;
	private TransactionService transactionService = null;
	private CategoryDao categoryDao = null;

	private CategoryDao mockCategoryDao = null;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {

		super.setUp();

		transactionDao = new TransactionDao();
		transactionService = new TransactionService();
		accountDao = new AccountDao();
		categoryDao = new CategoryDao();
	}

	@After
	public void tearDown() throws Exception {
		super.tearDown();
	}

	@Test
	public final void testFindByIdSuccess() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees"));

		replayMocks();

		Transaction ret = transactionDao.findById(Integer.valueOf(1));

		assertNotNull(ret);
	}

	@Test
	public final void testFindByAccountTypeSuccess() {

		replayMocks();

		transactionDao.setCategoryDao(categoryDao);

		List<Transaction> list = transactionDao.findByAccountType("Checking");

		assertNotNull(list);
		assertEquals(2, list.size());
		transactionService.setAccountDao(accountDao);
		// Check transaction total
		Float total = transactionService.calculateTransactionsTotal(list);

		assertEquals(Float.valueOf("129.00"), total);
	}

	@Test
	public final void testFindByAnyCompositeTransactionByCategory() {

		Category cat = new Category(2, "Restaurants");

		replayMocks();
		transactionDao.setCategoryDao(categoryDao);
		List<Transaction> list = transactionDao.findByAny(cat, null, null,
				null, null, null);

		assertNotNull(list);
		assertEquals(2, list.size());

		transactionService.setAccountDao(accountDao);

		// Check transaction total
		Float total = transactionService.calculateTransactionsTotal(list, cat);

		assertEquals(Float.valueOf("143.68"), total);
	}

	@Test
	public final void testFindByAnyCompositeTransactionByCategoryDateKeyword() {

		replayMocks();

		Category cat = new Category(5, "Gas");
		transactionDao.setCategoryDao(categoryDao);
		List<Transaction> list = transactionDao.findByAny(cat,
				new GregorianCalendar(2013, 1, 20).getTime(), null, null,
				"gas", null);

		assertNotNull(list);
		assertEquals(1, list.size());
		transactionService.setAccountDao(accountDao);

		// Check transaction total
		Float total = transactionService.calculateTransactionsTotal(list, cat);

		assertEquals(Float.valueOf("50.00"), total);
	}

	@Test
	public final void testFindByAnyStartDate() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(16);

		replayMocks();

		Calendar c = new GregorianCalendar(2013, 0, 1);
		List<Transaction> list = transactionDao.findByAny(null, c.getTime(),
				null, null, null, null);

		assertNotNull(list);
		assertEquals(2, list.size());
	}

	@Test
	public final void testFindByAnyEndDate() {

		Calendar c = new GregorianCalendar(2013, 0, 1);

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(16);

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, c.getTime(),
				null, null, null, null);

		assertNotNull(list);
		assertEquals(2, list.size());
	}

	@Test
	public final void testFindByAnyKeyword() {
		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees"));

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				null, "Fee", null);

		assertNotNull(list);
		assertEquals(1, list.size());
	}

	@Test
	public final void testFindByAnyKeywordsWithSpaces() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees"));

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				null, "Fee", null);

		assertNotNull(list);
		assertEquals(1, list.size());
	}

	@Test
	public final void testFindByAnyKeywordsWithSpacesAndDoubleQuotes() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(2);

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				null, "Fee \"Local Diner\"", null);

		assertNotNull(list);
		assertEquals(2, list.size());
		transactionService.setAccountDao(accountDao);

		// Check transaction total
		Float total = transactionService.calculateTransactionsTotal(list);

		assertEquals(Float.valueOf("122.68"), total);
	}

	@Test
	public final void testFindByAnyAccount() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees"));

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				"Visa Card", null, null);

		assertNotNull(list);
		assertEquals(1, list.size());
	}

	@Test
	public final void testFindByAnyConfirmed() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(17);

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				null, null, Boolean.FALSE);

		assertNotNull(list);
		assertEquals(3, list.size());
	}

	@Test
	public final void testFindByAnyAllNull() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(17);

		replayMocks();

		List<Transaction> list = transactionDao.findByAny(null, null, null,
				null, null, null);

		assertNotNull(list);
		assertEquals(3, list.size());
	}

	@Test
	public final void testFindByAnyAccountAndDate() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees"));

		replayMocks();

		Calendar start = new GregorianCalendar(2012, 0, 1);
		Calendar end = new GregorianCalendar(2013, 10, 1);

		List<Transaction> list = transactionDao.findByAny(null,
				start.getTime(), end.getTime(), "Visa Card", null, null);

		assertNotNull(list);
		assertEquals(1, list.size());
	}

	@Test
	public final void testFindByParentIdSuccess() {

		transactionDao.setCategoryDao(mockCategoryDao);

		expect(mockCategoryDao.findById(anyInt())).andReturn(
				new Category(null, "Fees")).times(2);

		replayMocks();

		List<Transaction> list = transactionDao.findByParentId(2);
		assertNotNull(list);
		assertEquals(2, list.size());
	}
}
